"""
参数解析模块
================

该模块负责解析read和write函数的各种输入参数格式，并将其转换为统一的内部表示形式。
"""


from typing import Any, Dict, List, Tuple, Union, Optional
from .typedef import FullReadType, FullWriteType, AddressType, ValueType, DataType, ReadOption, WriteOption
from .data_type_utils import normalize_data_type
from ..utils.logger import get_logger,default_logger


class ParamParser:
    """参数解析器"""

    def __init__(self):
        """
        初始化参数解析器
        """
        self.logger = default_logger.getChild("ParamParser")

    @staticmethod
    def _parse_common_address_fields(address: Union[dict, list], result: Dict[str, Any],
                                   has_values: bool = False) -> None:
        """
        解析地址参数中的通用字段

        Args:
            address: 地址参数（字典或列表）
            result: 结果字典
            has_values: 是否包含值字段（用于写入操作）
        """
        # 提取地址相关字段
        if 'address' in address:
            result['addresses'] = [address['address']]
        elif 'addresses' in address:
            result['addresses'] = address['addresses']

        # 提取数据类型字段
        if 'data_type' in address:
            result['data_types'] = [address['data_type']]
        elif 'data_types' in address:
            result['data_types'] = address['data_types']

        # 提取选项字段
        if 'option' in address:
            result['options'] = [address['option']]
        elif 'options' in address:
            result['options'] = address['options']

        # 提取长度字段
        if 'length' in address:
            result['lengths'] = [address['length']]
        elif 'lengths' in address:
            result['lengths'] = address['lengths']

        # 如果是写入操作，提取值字段
        if has_values:
            if 'value' in address:
                result['values'] = [address['value']]
            elif 'values' in address:
                result['values'] = address['values']

    @staticmethod
    def _parse_tuple_address(address: tuple, result: Dict[str, Any],
                           has_values: bool = False) -> Dict[str, Any]:
        """
        解析元组类型的地址参数

        Args:
            address: 元组地址参数
            result: 结果字典
            has_values: 是否包含值字段（用于写入操作）

        Returns:
            Dict[str, Any]: 解析后的地址信息
        """
        # 检查是否是简单格式(address, data_type)或(address, value)
        if len(address) == 2 and not isinstance(address[0], (list, tuple, dict)):
            result['addresses'].append(address[0])
            if has_values:
                # 写入操作 (address, value)
                result['values'].append(address[1])
            else:
                # 读取操作 (address, data_type)
                result['data_types'].append(address[1])
            return result

        # 检查是否是带数据类型的元组格式
        if len(address) >= 3:
            # 读取操作: (address, data_type, option/length)
            # 写入操作: (address, value, data_type) 或 (address, value, data_type, option/length)
            result['addresses'].append(address[0])

            if has_values:
                # 写入操作
                result['values'].append(address[1])
                result['data_types'].append(address[2])
            else:
                # 读取操作
                result['data_types'].append(address[1])

            # 处理可选参数
            if len(address) >= 3:
                # 根据操作类型确定第三个参数的含义
                param_index = 2 if not has_values else 3
                if len(address) > param_index:
                    if isinstance(address[param_index], str):
                        result['options'].append(address[param_index])
                    else:
                        result['lengths'].append(address[param_index])

            # 处理更多参数
            if len(address) >= 4:
                # 根据操作类型确定第四个参数的含义
                param_index = 3 if not has_values else 4
                if len(address) > param_index:
                    if isinstance(address[param_index], str):
                        result['options'].append(address[param_index])
                    else:
                        result['lengths'].append(address[param_index])

        return result

    @staticmethod
    def _parse_list_address(address: list, result: Dict[str, Any],
                          has_values: bool = False) -> Dict[str, Any]:
        """
        解析列表类型的地址参数

        Args:
            address: 列表地址参数
            result: 结果字典
            has_values: 是否包含值字段（用于写入操作）

        Returns:
            Dict[str, Any]: 解析后的地址信息
        """
        result['address_type'] = 'batch'

        # 检查列表元素类型
        if all(isinstance(item, dict) for item in address):
            # 列表中的字典元素处理
            result['addresses'] = [item['address'] for item in address]

            if 'data_type' in address[0]:
                result['data_types'] = [item.get('data_type') for item in address]
            if 'option' in address[0]:
                result['options'] = [item.get('option') for item in address]
            if 'length' in address[0]:
                result['lengths'] = [item.get('length') for item in address]

            # 如果是写入操作，提取值字段
            if has_values:
                if 'value' in address[0]:
                    result['values'] = [item.get('value') for item in address]

        elif all(isinstance(item, tuple) for item in address):
            # [(address, data_type/value, ...), ...] 格式
            for item in address:
                result['addresses'].append(item[0])

                if has_values:
                    # 写入操作
                    result['values'].append(item[1])
                    if len(item) >= 3:
                        # 处理第三个参数，可能是DataType枚举或数据类型字符串
                        third_param = item[2]
                        if isinstance(third_param, DataType):
                            result['data_types'].append(third_param.value)
                        else:
                            result['data_types'].append(third_param)
                else:
                    # 读取操作
                    second_param = item[1]
                    if isinstance(second_param, DataType):
                        result['data_types'].append(second_param.value)
                    else:
                        result['data_types'].append(second_param)

                if len(item) >= 3:
                    # 根据操作类型确定第三个参数的含义
                    param_index = 2 if not has_values else 3
                    if len(item) > param_index:
                        if isinstance(item[param_index], str):
                            result['options'].append(item[param_index])
                        else:
                            result['lengths'].append(item[param_index])
                if len(item) >= 4:
                    # 根据操作类型确定第四个参数的含义
                    param_index = 3 if not has_values else 4
                    if len(item) > param_index:
                        if isinstance(item[param_index], str):
                            result['options'].append(item[param_index])
                        else:
                            result['lengths'].append(item[param_index])
        else:
            # [address, ...] 格式（只有地址）
            result['addresses'] = address

        return result

    @staticmethod
    def parse_read_address(address: FullReadType) -> Dict[str, Any]:
        """
        解析读取地址参数

        Args:
            address: 各种格式的地址参数

        Returns:
            Dict[str, Any]: 解析后的地址信息，包含:
                - address_type: 地址类型
                - addresses: 地址列表
                - data_types: 数据类型列表（如果提供）
                - options: 选项列表（如果提供）
                - lengths: 长度列表（如果提供）
        """
        logger = default_logger.getChild("ParamParser")
        logger.debug(f"开始解析读取地址参数: {address}")

        result = {
            'address_type': 'single',
            'addresses': [],
            'data_types': [],
            'options': [],
            'lengths': []
        }

        try:
            # 处理字典类型配置
            if isinstance(address, dict):
                result['address_type'] = 'config'
                ParamParser._parse_common_address_fields(address, result, has_values=False)
                logger.debug(f"字典类型地址解析完成: {result}")
                return result

            # 处理元组类型
            if isinstance(address, tuple):
                ParamParser._parse_tuple_address(address, result, has_values=False)
                logger.debug(f"元组类型地址解析完成: {result}")
                return result

            # 处理列表类型
            if isinstance(address, list):
                ParamParser._parse_list_address(address, result, has_values=False)
                logger.debug(f"列表类型地址解析完成: {result}")
                return result

            # 处理单个地址
            result['addresses'].append(address)
            logger.debug(f"单个地址解析完成: {result}")
            return result

        except Exception as e:
            logger.error(f"解析读取地址参数时发生错误: {str(e)}", exc_info=True)
            raise ValueError(f"解析读取地址参数时发生错误: {str(e)}")

    @staticmethod
    def parse_write_address(address: FullWriteType) -> Dict[str, Any]:
        """
        解析写入地址参数

        Args:
            address: 各种格式的地址参数

        Returns:
            Dict[str, Any]: 解析后的地址信息，包含:
                - address_type: 地址类型
                - addresses: 地址列表
                - values: 值列表
                - data_types: 数据类型列表（如果提供）
                - options: 选项列表（如果提供）
                - lengths: 长度列表（如果提供）
        """
        logger = default_logger.getChild("ParamParser")
        logger.debug(f"开始解析写入地址参数: {address}")

        result = {
            'address_type': 'single',
            'addresses': [],
            'values': [],
            'data_types': [],
            'options': [],
            'lengths': []
        }

        try:
            # 处理字典类型配置
            if isinstance(address, dict):
                # 检查是否为批量写入格式（字典中包含多个地址和值）
                if 'addresses' in address and 'values' in address:
                    result['address_type'] = 'batch'
                    result['addresses'] = address['addresses']
                    result['values'] = address['values']

                    # 提取数据类型字段
                    if 'data_type' in address:
                        result['data_types'] = [address['data_type']]
                    elif 'data_types' in address:
                        result['data_types'] = address['data_types']

                    # 提取选项字段
                    if 'option' in address:
                        result['options'] = [address['option']]
                    elif 'options' in address:
                        result['options'] = address['options']

                    # 提取长度字段
                    if 'length' in address:
                        result['lengths'] = [address['length']]
                    elif 'lengths' in address:
                        result['lengths'] = address['lengths']
                else:
                    # 单个配置写入
                    result['address_type'] = 'config'
                    ParamParser._parse_common_address_fields(address, result, has_values=True)

                logger.debug(f"字典类型地址解析完成: {result}")
                return result

            # 处理元组类型
            if isinstance(address, tuple):
                ParamParser._parse_tuple_address(address, result, has_values=True)
                logger.debug(f"元组类型地址解析完成: {result}")
                return result

            # 处理列表类型
            if isinstance(address, list):
                ParamParser._parse_list_address(address, result, has_values=True)
                logger.debug(f"列表类型地址解析完成: {result}")
                return result

            # 处理单个地址（这种情况在写入中较少见）
            result['addresses'].append(address)
            logger.debug(f"单个地址解析完成: {result}")
            return result

        except Exception as e:
            logger.error(f"解析写入地址参数时发生错误: {str(e)}", exc_info=True)
            raise

    @staticmethod
    def parse_positional_args(*args, operation_type: str = "read") -> Dict[str, Any]:
        """
        解析位置参数

        Args:
            *args: 位置参数
            operation_type: 操作类型，"read" 或 "write"

        Returns:
            Dict[str, Any]: 解析后的配置参数
        """
        logger = default_logger.getChild("ParamParser")
        logger.debug(f"开始解析位置参数: {args}")

        config = {}

        # 定义已知的数据类型列表（不区分大小写）
        known_data_types = [
            "null", "boolean", "sbyte", "byte", "int16", "uint16", "int32", "uint32",
            "int64", "uint64", "float", "double", "string", "datetime", "guid",
            "bytestring", "xmlelement", "nodeid", "expandednodeid", "statuscode",
            "qualifiedname", "localizedtext", "extensionobject", "datavalue",
            "variant", "diagnosticinfo", "auto"
        ]

        try:
            for arg in args:
                # 如果参数是字符串
                if isinstance(arg, str):
                    # 检查是否为已知的数据类型（不区分大小写）
                    if arg.lower() in known_data_types and 'data_type' not in config:
                        # 使用统一的数据类型标准化函数
                        config['data_type'] = normalize_data_type(arg)
                        logger.debug(f"解析到数据类型参数: {arg} -> {config['data_type']}")
                    # 检查是否为读取选项
                    elif operation_type == "read" and arg.lower() in ['sync', 'async'] and 'sync' not in config:
                        config['sync'] = arg.lower() == 'sync'
                    # 检查是否为写入选项
                    elif operation_type == "write" and arg.lower() in ['sync', 'async'] and 'sync' not in config:
                        config['sync'] = arg.lower() == 'sync'
                # 如果参数是列表且所有元素都是字符串，可能是数据类型列表
                elif isinstance(arg, list) and all(isinstance(item, str) for item in arg):
                    # 检查列表中的所有元素是否都是已知的数据类型
                    if all(item.lower() in known_data_types for item in arg) and 'data_type' not in config:
                        # 标准化列表中的所有数据类型
                        normalized_types = [normalize_data_type(item) for item in arg]
                        config['data_type'] = normalized_types
                        logger.debug(f"解析到数据类型列表参数: {arg} -> {normalized_types}")
                # 如果参数是列表且包含DataType枚举，处理为数据类型列表
                elif isinstance(arg, list) and all(isinstance(item, (str, DataType)) for item in arg):
                    # 检查是否包含DataType枚举或者已知的字符串类型
                    valid_data_types = all(
                        isinstance(item, DataType) or item.lower() in known_data_types
                        for item in arg
                    )
                    if valid_data_types and 'data_type' not in config:
                        # 标准化列表中的所有数据类型（处理枚举和字符串）
                        normalized_types = []
                        for item in arg:
                            if isinstance(item, DataType):
                                normalized_types.append(item.value)
                            else:
                                normalized_types.append(normalize_data_type(item))
                        config['data_type'] = normalized_types
                        logger.debug(f"解析到包含DataType枚举的数据类型列表参数: {arg} -> {normalized_types}")
                # 如果参数是数字，可能是超时设置
                elif isinstance(arg, (int, float)) and 'timeout' not in config:
                    config['timeout'] = arg
                    logger.debug(f"解析到超时参数: {arg}")
                # 如果参数是布尔值
                elif isinstance(arg, bool) and 'sync' not in config:
                    config['sync'] = arg
                    logger.debug(f"解析到同步参数: {arg}")
                # 如果参数是DataType枚举
                elif isinstance(arg, DataType) and 'data_type' not in config:
                    config['data_type'] = arg.value
                    logger.debug(f"解析到DataType枚举参数: {arg} -> {arg.value}")
                # 如果参数是WriteOption枚举（仅用于写入）
                elif operation_type == "write" and isinstance(arg, WriteOption) and 'sync' not in config:
                    config['sync'] = arg == WriteOption.SYNC
                    logger.debug(f"解析到WriteOption枚举参数: {arg} -> {config['sync']}")
                # 如果参数是ReadOption枚举（仅用于读取）
                elif operation_type == "read" and isinstance(arg, ReadOption) and 'sync' not in config:
                    config['sync'] = arg == ReadOption.SYNC
                    logger.debug(f"解析到ReadOption枚举参数: {arg} -> {config['sync']}")

            logger.debug(f"位置参数解析完成: {config}")
            return config
        except Exception as e:
            logger.error(f"解析位置参数时发生错误: {str(e)}", exc_info=True)
            raise

    @staticmethod
    def parse_keyword_args(**kwargs) -> Dict[str, Any]:
        """
        解析关键字参数

        Args:
            **kwargs: 关键字参数

        Returns:
            Dict[str, Any]: 解析后的配置参数
        """
        logger = default_logger.getChild("ParamParser")
        logger.debug(f"开始解析关键字参数: {kwargs}")

        try:
            # 对关键字参数中的data_type进行标准化处理
            if 'data_type' in kwargs:
                # 如果是DataType枚举，获取其值；否则进行标准化处理
                if isinstance(kwargs['data_type'], DataType):
                    kwargs['data_type'] = kwargs['data_type'].value
                    logger.debug(f"标准化DataType枚举参数: {kwargs['data_type']}")
                # 如果是列表且包含DataType枚举，处理为标准化列表
                elif isinstance(kwargs['data_type'], list):
                    normalized_types = []
                    for item in kwargs['data_type']:
                        if isinstance(item, DataType):
                            normalized_types.append(item.value)
                        else:
                            normalized_types.append(normalize_data_type(item))
                    kwargs['data_type'] = normalized_types
                    logger.debug(f"标准化包含DataType枚举的数据类型列表: {kwargs['data_type']}")
                else:
                    kwargs['data_type'] = normalize_data_type(kwargs['data_type'])
                    logger.debug(f"标准化数据类型参数: {kwargs['data_type']}")

            logger.debug(f"关键字参数解析完成: {kwargs}")
            return kwargs
        except Exception as e:
            logger.error(f"解析关键字参数时发生错误: {str(e)}", exc_info=True)
            raise

    @staticmethod
    def merge_configs(pos_config: Dict[str, Any], kw_config: Dict[str, Any]) -> Dict[str, Any]:
        """
        合并位置参数和关键字参数配置

        Args:
            pos_config: 位置参数配置
            kw_config: 关键字参数配置

        Returns:
            Dict[str, Any]: 合并后的配置
        """
        logger = default_logger.getChild("ParamParser")
        logger.debug(f"开始合并配置: 位置参数={pos_config}, 关键字参数={kw_config}")

        try:
            # 关键字参数优先级更高，覆盖位置参数
            merged_config = pos_config.copy()
            merged_config.update(kw_config)

            logger.debug(f"配置合并完成: {merged_config}")
            return merged_config
        except Exception as e:
            logger.error(f"合并配置时发生错误: {str(e)}", exc_info=True)
            raise

    @staticmethod
    def validate_read_params(parsed_params: Dict[str, Any]) -> bool:
        """
        验证解析后的读取参数

        Args:
            parsed_params: 解析后的参数

        Returns:
            bool: 参数是否有效
        """
        logger = default_logger.getChild("ParamParser")
        logger.debug(f"开始验证读取参数: {parsed_params}")

        try:
            # 检查基本必需字段
            if not parsed_params.get('addresses'):
                logger.warning("参数验证失败: 缺少地址信息")
                return False

            # 检查数据类型列表长度
            addresses = parsed_params.get('addresses', [])
            data_types = parsed_params.get('data_types', [])
            if data_types and len(data_types) != len(addresses) and len(data_types) != 1:
                # data_types可以是与地址一一对应，或者只有一个通用类型
                logger.warning(f"参数验证失败: 数据类型数量({len(data_types)})与地址数量({len(addresses)})不匹配")
                return False

            # 检查选项列表长度
            options = parsed_params.get('options', [])
            if options and len(options) != len(addresses) and len(options) != 1:
                logger.warning(f"参数验证失败: 选项数量({len(options)})与地址数量({len(addresses)})不匹配")
                return False

            # 检查长度列表长度
            lengths = parsed_params.get('lengths', [])
            if lengths and len(lengths) != len(addresses) and len(lengths) != 1:
                logger.warning(f"参数验证失败: 长度数量({len(lengths)})与地址数量({len(addresses)})不匹配")
                return False

            logger.debug("读取参数验证通过")
            return True
        except Exception as e:
            logger.error(f"验证读取参数时发生错误: {str(e)}", exc_info=True)
            return False

    @staticmethod
    def validate_write_params(parsed_params: Dict[str, Any]) -> bool:
        """
        验证解析后的写入参数

        Args:
            parsed_params: 解析后的参数

        Returns:
            bool: 参数是否有效
        """
        logger = default_logger.getChild("ParamParser")
        logger.debug(f"开始验证写入参数: {parsed_params}")

        try:
            # 检查基本必需字段
            if not parsed_params.get('addresses'):
                logger.warning("参数验证失败: 缺少地址信息")
                return False

            # 检查地址和值的数量是否匹配
            addresses = parsed_params.get('addresses', [])
            values = parsed_params.get('values', [])

            # 如果有值列表，必须与地址列表长度一致
            if values and len(addresses) != len(values):
                logger.warning(f"参数验证失败: 地址数量({len(addresses)})与值数量({len(values)})不匹配")
                return False

            # 检查数据类型列表长度
            data_types = parsed_params.get('data_types', [])
            if data_types and len(data_types) != len(addresses) and len(data_types) != 1:
                # data_types可以是与地址一一对应，或者只有一个通用类型
                logger.warning(f"参数验证失败: 数据类型数量({len(data_types)})与地址数量({len(addresses)})不匹配")
                return False

            # 检查选项列表长度
            options = parsed_params.get('options', [])
            if options and len(options) != len(addresses) and len(options) != 1:
                logger.warning(f"参数验证失败: 选项数量({len(options)})与地址数量({len(addresses)})不匹配")
                return False

            # 检查长度列表长度
            lengths = parsed_params.get('lengths', [])
            if lengths and len(lengths) != len(addresses) and len(lengths) != 1:
                logger.warning(f"参数验证失败: 长度数量({len(lengths)})与地址数量({len(addresses)})不匹配")
                return False

            logger.debug("写入参数验证通过")
            return True
        except Exception as e:
            logger.error(f"验证写入参数时发生错误: {str(e)}", exc_info=True)
            return False